use dioxus::html::audio;
use rodio::{Decoder, OutputStream, Sink, Source, buffer};
use std::fs::File;
use std::io::{BufReader, Read, Write};

//***********************************************************/
// 1) cargo.toml 添加依赖项播放音乐的库
//      [dependencies]
//      rodio = "0.15.0"
// 2) 1.mp3 2.mp3 放到项目根路径下
// 3) 测试使用std库include_bytes!宏功能
//
// 知识点: \
//    1) Vec<u8> 转换为 Vec<f32>
//    2) Vec<f32> 转换为 Vec<u8>
//    3) api flat_map to_ne_bytes
//***********************************************************/
pub fn load_mp3_files(
    file_path1: &str,
    file_path2: &str,
) -> Result<(Vec<f32>, Vec<f32>), Box<dyn std::error::Error>> {
    // 打开并解码第一个 MP3 文件
    let file1 = File::open(file_path1)?;
    let source1 = Decoder::new(BufReader::new(file1))?.convert_samples::<f32>(); // 显式转换为 f32 格式
    let buffered1: Vec<f32> = source1.collect(); // 缓冲音频数据
    println!("MP3 file 1 decoded successfully!");

    // 打开并解码第二个 MP3 文件
    let file2 = File::open(file_path2)?;
    let source2 = Decoder::new(BufReader::new(file2))?.convert_samples::<f32>(); // 显式转换为 f32 格式
    let buffered2: Vec<f32> = source2.collect(); // 缓冲音频数据
    println!("MP3 file 2 decoded successfully!");

    // 返回解码后的音频数据
    Ok((buffered1, buffered2))
}

pub fn play_audio(audio_data: &[f32]) -> Result<(), Box<dyn std::error::Error>> {
    // 创建音频输出流
    let (_stream, stream_handle) = OutputStream::try_default()?;
    let sink = Sink::try_new(&stream_handle)?;

    // 使用 SamplesBuffer 包装音频数据
    let source = rodio::buffer::SamplesBuffer::new(1, 44100, audio_data); // 单声道，44100Hz
    sink.append(source);
    println!("Playing audio...");

    // 等待音频播放完成
    sink.sleep_until_end();
    Ok(())
}
fn main() {
    //test();
    test2();
}
/// 尝试将mp3用rodio库解码后保存为文件,再读取文件并播放
/// 尝试结果可以播放
/*
    flat_map() 方法将 Vec<f32> 中的每个元素映射到一个迭代器，然后迭代器被 flat_map() 方法展开，得到一个迭代器，这个迭代器包含 Vec<f32> 中的所有元素。
    to_ne_bytes() 方法将 f32 值转换为原生字节数组，并返回一个字节数组。
    collect() 方法将迭代器转换为 Vec<u8>。

    字节序: to_ne_bytes() 使用的是原生字节序（native endianness），这取决于运行系统的架构。
    如果需要特定的字节序（如大端序或小端序），可以使用 to_be_bytes() 或 to_le_bytes()。
*/
fn test() {
    let (audio_data1, audio_data2) = load_mp3_files(".\\1.mp3", ".\\2.mp3").unwrap();
    //创建一个可写二进制文件,
    {
        let mut file = std::fs::File::create("audio_start.bin").unwrap();
        let vec_u8: Vec<u8> = audio_data1
            .iter()
            .flat_map(|&num| num.to_ne_bytes())
            .collect();
        file.write_all(&vec_u8).unwrap();
        file.flush();
    }
    //读取二进制文件
    let mut file = std::fs::File::open("audio_start.bin").unwrap();
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer).unwrap();
    let vec_f32: Vec<f32> = buffer
        .chunks_exact(4) //用于将 Vec<u8> 分割成每 4 个字节的块，因为一个 f32 是 4 字节大小
        .map(|bytes| {
            let mut arr = [0u8; 4];
            arr.copy_from_slice(bytes);
            f32::from_ne_bytes(arr)
        })
        .collect();

    play_audio(&vec_f32).unwrap();
}

/// 尝试将mp3用include_bytes!()引入二进制文件,再读读取文件并播放
/// 尝试结果可以播放
fn test2() {
    let audio_data = include_bytes!("..\\audio_start.bin");
    let vec_f32: Vec<f32> = audio_data
        .chunks_exact(4)
        .map(|bytes| {
            let mut arr = [0u8; 4];
            arr.copy_from_slice(bytes);
            f32::from_ne_bytes(arr)
        })
        .collect();

    play_audio(&vec_f32).unwrap();
}
